#include "music.h"

#ifndef SKYID_DISABLE_SOUND
namespace SkyID
{

MusicOGG::MusicOGG(Reader *reader)
{
	mBuffer = new ALuint[OGG_BUFFERS_COUNT];
	alGenBuffers(OGG_BUFFERS_COUNT, mBuffer);
	setValid(check());
	mReader = reader;
}

MusicOGG::~MusicOGG()
{
	stop();
	cleanBuffer();
	alDeleteBuffers(OGG_BUFFERS_COUNT, mBuffer);
	check();
	ov_clear(&mOggStream);
	delete[] mBuffer;
	mBuffer = NULL;
}

bool MusicOGG::open(Reader *reader)
{
	LOG_ASSERT(reader && reader->isValid());
	mReader = reader;

	if (!mReader->reset())
		return false;

	ov_callbacks callbacks;
	callbacks.read_func  = HelperOggRead;
	callbacks.seek_func  = NULL;
	callbacks.close_func = NULL;
	callbacks.tell_func  = NULL;

	if (ov_open_callbacks(reader, &mOggStream, NULL, 0, callbacks) < 0)
	{
		LOG_MSG("MusicOGG: wrong file signature\n");
		return false;
	}

	vorbis_info* info = ov_info(&mOggStream, -1);
	vorbis_comment* comment = ov_comment(&mOggStream, -1);

	mFormat = info->channels==1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
	mFrequency = info->rate;

	return true;
}

void MusicOGG::play()
{
	if (!open(mReader))
		return;
	cleanBuffer();
	for (unsigned int i=0; i<OGG_BUFFERS_COUNT; ++i)
		if (!fillBuffer(mBuffer[i]))
			return;
	alSourceQueueBuffers(mID, OGG_BUFFERS_COUNT, mBuffer);
	alSourcePlay(mID);
}

bool MusicOGG::fillBuffer(ALuint buffer)
{
	char data[OGG_BUFFER_SIZE];
	int size = 0, result = 1, bs;

	while (size<OGG_BUFFER_SIZE && result)
	{
		result = ov_read(&mOggStream, data + size, OGG_BUFFER_SIZE - size, 0, 2, 1, &bs);
		if (result < 0)
		{
			LOG_MSG("MusicOGG: error streaming OGG file");
			return false;
		}
		size += result;
	}

	alBufferData(buffer, mFormat, data, size, mFrequency);
	check();

	return size > 0;
}

} // namespace SkyID
#endif // SKYID_DISABLE_SOUND
